﻿using Microsoft.WindowsAzure.Storage.Table;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace POC.Azure.Storage
{
    public class TableStorageRespository<T> : ITableStorageRespository<T>
    {
        protected AzureAccount _account;
        protected CloudTableClient _client;
        protected CloudTable _table;
        protected string StorageTableName;

        public TableStorageRespository()
        {
            _account = new AzureAccount(true);
        }
        public TableStorageRespository(AzureAccount account)
        {
            _account = account;
        }
        public TableStorageRespository(AzureAccount account, string partitionName)
        {
            _account = account;
            StorageTableName = Regex.Replace(partitionName, "[^a-zA-Z0-9]+", "", RegexOptions.Compiled);
        }
        public void InitializeRepository()
        {
            if (_table == null)
            {
                _client = _account.CloudAccount.CreateCloudTableClient();

                _table = _client.GetTableReference(StorageTableName);
            }
            _table.CreateIfNotExists();
        }
        public List<ITableEntity> GetEntries(TableQuery rangeQuery)
        {
            var rows = _table.ExecuteQuery(rangeQuery);
            return rows.ToList<ITableEntity>();
        }
        public ITableEntity GetEntry(TableQuery rangeQuery)
        {
            var rows = _table.ExecuteQuery(rangeQuery);
            var t = rows.FirstOrDefault<ITableEntity>();
            return t;
        }
        public Task UpdateEntry(T t, bool lazyExecute = false)
        {
            ITableEntity entry = t as ITableEntity;
            Task<TableResult> task = null;
            if (_table == null)
            {
                InitializeRepository();
            }
            TableOperation saveOperation = TableOperation.InsertOrMerge(entry);
            if (lazyExecute)
            {
                task = Task<TableResult>.Factory.FromAsync(_table.BeginExecute, _table.EndExecute, saveOperation, null);
            }
            else
            {
                _table.Execute(saveOperation);
            }
            return task;
        }
        public Task DeleteEntry(T t, bool lazyExecute = false)
        {
            ITableEntity entry = t as ITableEntity;
            Task<TableResult> task = null;
            if (_table == null)
            {
                InitializeRepository();
            }
            TableOperation deleteOperation = TableOperation.Delete(entry);
            if (lazyExecute)
            {
                task = Task<TableResult>.Factory.FromAsync(_table.BeginExecute, _table.EndExecute, deleteOperation, null);
            }
            else
            {
                _table.Execute(deleteOperation);
            }
            return task;
        }
        public Task AddEntry(T t, bool lazyExecute=false)
        {
            ITableEntity entry = t as ITableEntity;
            Task<TableResult> task = null;
            if (_table == null)
            {
                InitializeRepository();
            }
            TableOperation insertOperation = TableOperation.Insert(entry);
            if (lazyExecute)
            {
                task = Task<TableResult>.Factory.FromAsync(_table.BeginExecute, _table.EndExecute, insertOperation, null);
            }
            else
            {
                _table.Execute(insertOperation);
            }
            return task;
        }
        public Task PutEntry(T t, bool lazyExecute = false)
        {
            ITableEntity entry = t as ITableEntity;
            Task<TableResult> task = null;
            if (_table == null)
            {
                InitializeRepository();
            }
            TableOperation insertOperation = TableOperation.Insert(entry);
            if (lazyExecute)
            {
                task = Task<TableResult>.Factory.FromAsync(_table.BeginExecute, _table.EndExecute, insertOperation, null);
            }
            else
            {
                _table.Execute(insertOperation);
            }
            return task;
        }
        public List<T> GetAllEntries(string[] columnsName = null)
        {
            List<T> entries = new List<T>();
            if (_table == null)
            {
                InitializeRepository();
            }
            string part = DateTime.Now.ToString("MM_yyyy");
            // Create the table query.
            TableQuery rangeQuery = new TableQuery().Where(
                TableQuery.CombineFilters(
                    TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, part),
                    TableOperators.And,
                    TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.NotEqual, "")));

            if (columnsName != null)
            {
                rangeQuery.SelectColumns = columnsName;
            }
            var rows = _table.ExecuteQuery(rangeQuery);
            //entries = rows.ToList<T>();
            return entries;
        }

        public IEnumerable<T> Get(string tableName, string partitionKey, IEnumerable<string> rowKeys)
        {
            CloudTableClient tableClient = _account.CloudAccount.CreateCloudTableClient();
            var context = tableClient.GetTableServiceContext();
            List<T> entries = new List<T>();
            return entries;
        }

    }
}
